#include "../include/collector.h"
#include "../include/pool.h"
#include "../include/line.h"
#include "../include/map.h"
#include "../include/queue.h"

void Collector_Init(Line *line, Collector *collector)
{
    collector->object = NULL;
    collector->line = line;
}

void mark(TValue value)
{
    if (!IS_OBJECT(value) || ((Object *)value.value.object)->color == WHITE)
    {
        return;
    }
    switch (value.category)
    {
    case T_MAP:
    {
        Map *map = (Map *)value.value.object;
        for (u_int i = 0; i < map->size; i++)
        {
            MapNode *node = &map->array[i];
            if (!IS_NULL(node->value))
            {
                mark(node->value);
                while (node->next != -1)
                {
                    node = &map->overflow[node->next];
                    mark(node->value);
                }
            }
        }
        break;
    }
    case T_QUEUE:
    {
        Queue *queue = (Queue *)value.value.object;
        queue->color = WHITE;
        for (u_int i = 0; i < queue->length; i++)
        {
            mark(Queue_Get(queue, i));
        }
        break;
    }
    case T_EXCEPTION:
    {
        Exception *exception = TO_EXCEPTION(value);
        mark(exception->value);
        break;
    }
    default:
        return;
    }
    ((Object *)value.value.object)->color = WHITE;
}

Line *Collector_GC(Collector *collector)
{
    Object *object = collector->object;
    while (object != NULL)
    {
        object->color = BLACK;
        object = object->next;
    }
    for (u_int i = 0; i < collector->line->closure_stack.length; i++)
    {
        // mark(TFUNCTION(Array_Get(&collector->line->stack, i, Function *)));
    }
    while (collector->object != NULL)
    {
        Object *next = collector->object->next;
        if (collector->object->color != WHITE)
        {
            collector->object->delete (collector->object);
            Globe_Free(collector->object);
        }
        else
        {
            collector->object->next = object;
            object = collector->object;
        }
        collector->object = next;
    }
    collector->object = object;
}
